home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Dots & Pixels
/
headers
/
flowdots.h
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-29
|
5KB
|
165 lines
#pragma once
//
// class flowdots is used for the rapid appliance of first order optic
// flow to large numbers of dots. A large speed increases is obtained by performing
// many operations in integers. At the same time the interface to the class uses
// doubles for ease of use.
// We store coordinates of dots in 16-bit signed fixed point format with an implied
// decimal point after the second bit. This limits the values of the numbers used
// to the range (-2.0, +2.0) (boundaries excluded)
//
// Two copies of the actual parameters of the flow are kept:
//
// 1. The user accessible ones, in doubles, and in degrees and per second
// 2. A copy in fixed-point quantities, in 'per stimulus frame period'
//
// The user can set 1. directly.
// When how_often (see below) is unequal to zero a call to 'changed()' computes 2.
// When how_often is zero, 2. is recomputed by every call to 'apply_flow', which
// is called by 'screendots::make_a_move'
//
// The translation from per-second parameters, as specified in the flowsettings
// (copy 1) to per-frame coordinates (copy 2), takes place via one of two methods.
// Firstly the user can call the constructor with how_often == 0 (or later call
// 'set_how_often()' to set it to zero). If this is done the routine keeps track of
// the time taken between subsequent calls of 'apply_flow' and scales the
// displacements accordingly. Alternatively when 'how_often' is unequal to zero it
// is assumed to signify the frequency (in Hz) with which 'apply_flow' gets called.
//
// Note that it generally is faster to explicitly set 'how_often' to something non-zero.
//
#define degrees * 0.0174532925199
#define degrees_per_second * 0.0174532925199
//
// 950502: deriving flowdots from 'flowparams'. This allows one to switch
// between different flow parameters at high speed, i.e. without having to
// call 'changed()'. One can now do:
//
// flowdots fd( 8, 100, 100, 1000, 10, 75.0);
// fd.rotation = 20;
// fd.changed();
// const flowparams rot_params = fd;
//
// fd.rotation = 0;
// fd.expansion = 1.1;
// fd.changed();
// const flowparams div_params = fd;
//
// while( !done)
// {
// fd.setsettings( rot_params);
// fd.make_a_move();
// fd.setsettings( div_params);
// fd.make_a_move();
// }
//
// However, calling
//
// void flowdots::setsettings( const flowparams &theparams);
//
// only makes sense when 'how_often' is unequal to zero. If it is zero (signalling
// that flowdots should figure out itself how often it gets called) flowdots
// recomputes the fixed-point parameters everytime new dot positions must be
// computed, thus overwriting any parameters present.
//
// if how_often then
// ============ ====
// == 0.0 use void setsettings( const flowsettings &thesettings);
// != 0.0 use void setsettings( const flowparams &theparams);
//
// The first one is always safe to use, but slower.
//
class flowparams
{
protected:
short x11;
short x12;
short x21;
short x22;
long trans_x;
long trans_y;
};
class flowdots : protected flowparams, public dotcollection,
public phaser, public flowsettings, public screendots
{
public:
flowdots( int numbits, int xpos, int ypos,
int aantaldots, int lifetime, double how_often = 0.0);
flowdots( int numbits, screen_position where,
int aantaldots, int lifetime, double how_often = 0.0);
void set_how_often( const double how_often);
//
// Both the 'setsettings' calls change the actual flow to be shown
// the one which uses 'flowparams' is faster, because it does not
// have to do the float-fixed conversion (by calling 'changed').
// This implies that calling 'changed' after calling
// flowdots::setsettings( const flowparams &theparams)
// is an error since the floating point flow parameters are not
// changed by that call.
//
void setsettings( const flowsettings &thesettings);
void setsettings( const flowparams &theparams);
void changed();
protected:
virtual void compute_addresses();
void apply_flow();
double framerate;
double updaterate;
int auto_timing; // flag
unsigned long time_of_last_apply_flow_call;
void compute_matrices();
static double scale( double orig, double updaterate);
private:
//
// we use 'short_long_hack' to split an unsigned long in two
// signed shorts (the unsigned long being returned by randomizer_step())
// (could move these to 'dotcollection' and add a member 'uniformize')
//
typedef struct two_shorts
{
short left;
short right;
};
typedef union short_long_hack
{
two_shorts shorties;
unsigned long ulong;
};
};
inline void flowdots::set_how_often( const double how_often)
{
if( how_often > 0.0)
{
auto_timing = false;
updaterate = how_often;
} else {
auto_timing = true;
}
time_of_last_apply_flow_call = 0L;
}
inline void flowdots::changed()
{
if( !auto_timing)
{
compute_matrices();
}
}
inline double flowdots::scale( double orig, double updaterate)
{
return( exp( log( orig) / updaterate));
}